using System;
using System.Configuration;
using System.Globalization;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.Web.Security;
using Lab620.WcfRadiusService.Contracts;

namespace Lab620.WcfRadiusService.Extentions
{
    public class RadiusBindingCollectionElement :
        StandardBindingCollectionElement<RadiusBinding, RadiusBindingConfigurationElement>
    {
    }

    public class RadiusBindingConfigurationElement : StandardBindingElement
    {
        public RadiusBindingConfigurationElement(string configurationName)
            : base(configurationName)
        {
        }

        public RadiusBindingConfigurationElement()
            : this(null)
        {
        }

        protected override Type BindingElementType
        {
            get { return typeof (RadiusBinding); }
        }

        [ConfigurationProperty(RadiusConfigurationStrings.SharedSecret)]
        public string SharedSecret
        {
            get { return (string) base[RadiusConfigurationStrings.SharedSecret]; }
            set { base[RadiusConfigurationStrings.SharedSecret] = value; }
        }

        [ConfigurationProperty(RadiusConfigurationStrings.ProfileSource)]
        public string ProfileSource
        {
            get { return (string) base[RadiusConfigurationStrings.ProfileSource]; }
            set { base[RadiusConfigurationStrings.ProfileSource] = value; }
        }

        [ConfigurationProperty(RadiusConfigurationStrings.MembershipProvider)]
        public string MembershipProvider
        {
            get { return (string)base[RadiusConfigurationStrings.MembershipProvider]; }
            set { base[RadiusConfigurationStrings.MembershipProvider] = value; }
        }


        protected override ConfigurationPropertyCollection Properties
        {
            get
            {
                ConfigurationPropertyCollection properties = base.Properties;
                properties.Add(new ConfigurationProperty(RadiusConfigurationStrings.ProfileSource,
                                                         typeof (string), null, null, null,
                                                         ConfigurationPropertyOptions.None));
                properties.Add(new ConfigurationProperty(RadiusConfigurationStrings.SharedSecret,
                                                         typeof (string), null, null, null,
                                                         ConfigurationPropertyOptions.None));
                properties.Add(new ConfigurationProperty(RadiusConfigurationStrings.MembershipProvider,
                                                         typeof (string), null, null, null,
                                                         ConfigurationPropertyOptions.None));
                return properties;
            }
        }

        protected override void InitializeFrom(Binding binding)
        {
            base.InitializeFrom(binding);
            var radiusBinding = (RadiusBinding) binding;

            SharedSecret = radiusBinding.SharedSecret;
            ProfileSource = radiusBinding.ProfileSource != null
                                ? radiusBinding.ProfileSource.GetType().FullName
                                : null;
        }

        protected override void OnApplyConfiguration(Binding binding)
        {
            if (binding == null)
                throw new ArgumentNullException("binding");

            if (binding.GetType() != typeof (RadiusBinding))
            {
                throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                          "Invalid type for binding. Expected type: {0}. Type passed in: {1}.",
                                                          typeof (RadiusBinding).AssemblyQualifiedName,
                                                          binding.GetType().AssemblyQualifiedName));
            }
            var radiusBinding = (RadiusBinding) binding;

            radiusBinding.SharedSecret = SharedSecret;

            if (string.IsNullOrEmpty(ProfileSource) && string.IsNullOrEmpty(MembershipProvider))
                throw new ConfigurationErrorsException("Profile Source Type or Membership Provider is not specified");

            object profileSource;
            if (!string.IsNullOrEmpty(MembershipProvider))
            {
                profileSource = Membership.Providers[MembershipProvider];
            }
            else
            {
                Type type = Type.GetType(ProfileSource);

                profileSource = Activator.CreateInstance(type);

                if (!(profileSource is IClearTextPasswordProvider) && !(profileSource is MembershipProvider))
                    throw new ConfigurationErrorsException(
                        "Supplied type does not inherit from ASP.NET MembershipProvider base nor implemements IClearTextPasswordProvider: " +
                        type.FullName);
            }

            radiusBinding.ProfileSource = profileSource;
        }
    }
}